import { useState, useCallback, useEffect } from 'react';
import { ethers, BigNumber } from 'ethers';
import swapFactory from '@/abi/uniswapFactory.json';
import swapRouter from '@/abi/uniswapRouter.json';
import BscAbi from '@/abi/BscAbi.json';
import pairABI from '@/abi/pair.json';
import { useWeb3React } from '@web3-react/core';

const UNISWAP_FACTORY_ADDRESS = '0x6725F303b657a9451d8BA641348b6761A6CC7a17';

const UNISWAP_ROUTER_ADDRESS = '0xD99D1c33F9fC3444f8101754aBC46c52416550D1';
const PAIR_ADDRESS = '0x209eBd953FA5e3fE1375f7Dd0a848A9621e9eaFc';
//const PAIR_ADDRESS='0x5d6F6F2f92b410E1652DD4958f73c928344C177C'
const UNISWAP_FACTORY_ABI = swapFactory;
const UNISWAP_ROUTER_ABI = swapRouter;
const ERC20_ABI = BscAbi.result;
const UNISWAP_PAIR_ABI = pairABI;

const TOKEN_A_ADDRESS = '0xaB1a4d4f1D656d2450692D237fdD6C7f9146e814';
// const TOKEN_B_ADDRESS='0xFC188334801943F6f74509Dc393b1e930755bcAB'
const TOKEN_B_ADDRESS = '0xFa60D973F7642B748046464e165A65B7323b0DEE';
// const UNISWAP_FACTORY_ADDRESS = '0x6725F303b657a9451d8BA641348b6761A6CC7a17';

// const UNISWAP_ROUTER_ADDRESS = '0xD99D1c33F9fC3444f8101754aBC46c52416550D1';

// const UNISWAP_FACTORY_ABI = uniswapFactory
// const UNISWAP_ROUTER_ABI = uniswapRouter
const useUniswapSwap = () => {
  const [provider, setProvider] =
    useState<ethers.providers.Web3Provider | null>(null);

  const [uniswapRouter, setUniswapRouter] = useState<ethers.Contract | null>(
    null,
  );
  const [tokenA, setTokenA] = useState<ethers.Contract | null>(null);
  const [tokenB, setTokenB] = useState<ethers.Contract | null>(null);
  const [pair, setPair] = useState<ethers.Contract | null>(null);

  // 初始化 Provider，并获取账号信息
  useEffect(() => {
    const initProvider = async () => {
      try {
        if (window.ethereum) {
          const providerInstance = new ethers.providers.Web3Provider(
            window.ethereum,
          );
          await window.ethereum.enable();
          setProvider(providerInstance);
        } else {
          throw new Error(
            'Please install MetaMask wallet extension or use other Web3 provider',
          );
        }
      } catch (error) {
        console.error(error);
      }
    };
    initProvider();
  }, []);

  // 初始化 Uniswap 相关合约实例
  useEffect(() => {
    if (provider) {
      const uniswapRouterInstance = new ethers.Contract(
        UNISWAP_ROUTER_ADDRESS,
        UNISWAP_ROUTER_ABI,
        provider,
      );
      setUniswapRouter(uniswapRouterInstance);

      const tokenAInstance = new ethers.Contract(
        TOKEN_A_ADDRESS,
        ERC20_ABI,
        provider.getSigner(), // 这里使用 Signer
      );
      setTokenA(tokenAInstance);

      const tokenBInstance = new ethers.Contract(
        TOKEN_B_ADDRESS,
        ERC20_ABI,
        provider.getSigner(), // 这里使用 Signer
      );
      setTokenB(tokenBInstance);

      const pairInstance = new ethers.Contract(
        PAIR_ADDRESS,
        UNISWAP_PAIR_ABI,
        provider,
      );
      setPair(pairInstance);
    }
  }, [provider]);
};

//创建Pair
export const useCreatePair = () => {
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState('');
  const [createdPairAddress, setCreatedPairAddress] = useState('');
  const { activate, account, library } = useWeb3React();

  const createPair = async (tokenA?: string, tokenB?: string) => {
    try {
      setIsLoading(true);
      const provider = new ethers.providers.Web3Provider(window.ethereum);
      console.log(provider, 'provider');
      const signer = provider.getSigner();
      const factory = new ethers.Contract(
        UNISWAP_FACTORY_ADDRESS,
        UNISWAP_FACTORY_ABI,
        signer,
      );
      console.log(factory, 'factory', tokenA, tokenB);
      const existingPairAddress = await factory.getPair(tokenA, tokenB);
      if (existingPairAddress !== ethers.constants.AddressZero) {
        console.log('Pair已经创建:', existingPairAddress);
        setError('Pair 已经创建:' + existingPairAddress);
        setCreatedPairAddress(existingPairAddress);
        return existingPairAddress;
      }

      const tx = await factory.createPair(tokenA, tokenB);
      console.log('tx', tx);
      await tx.wait();
      const filter = factory.filters.PairCreated(null, null, null);
      console.log(filter, 'tx', tx);
      const logs = await factory.queryFilter(filter, tx.blockHash);
      // const pairAddress = logs;
      console.log(logs, 'logs');
      const pairAddress = await factory.getPair(tokenA, tokenB);
      setCreatedPairAddress(pairAddress);
    } catch (err: any) {
      console.log(err, 'err');
      setError(err.message);
    } finally {
      setIsLoading(false);
    }
  };

  return { createPair, isLoading, error, createdPairAddress };
};

//获取所有Pair
export const useGetAllPairs = () => {
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState('');
  const [allPairs, setAllPairs] = useState([]);

  const getAllPairs = async () => {
    try {
      setIsLoading(true);
      const provider = new ethers.providers.Web3Provider(window.ethereum);
      const factory = new ethers.Contract(
        UNISWAP_FACTORY_ADDRESS,
        UNISWAP_FACTORY_ABI,
        provider,
      );
      const length = await factory.allPairsLength();
      let pairs: any = [];
      for (let i = 0; i < length; i++) {
        pairs.push(await factory.allPairs(i));
      }
      setAllPairs(pairs);
      console.log(pairs, 'allPairs');
    } catch (err: any) {
      setError(err.message);
    } finally {
      setIsLoading(false);
    }
  };

  return { getAllPairs, isLoading, error, allPairs };
};

//交换代币
export const useSwapTokens = () => {
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState('');
  const [txHash, setTxHash] = useState('');

  const swapTokens = async (
    tokenIn: string,
    tokenOut: string,
    amountIn: number,
    amountOutMin: number,
    recipient: string,
  ) => {
    try {
      setIsLoading(true);
      const provider = new ethers.providers.Web3Provider(window.ethereum);
      const signer = provider.getSigner();
      const router = new ethers.Contract(
        UNISWAP_ROUTER_ADDRESS,
        UNISWAP_ROUTER_ABI,
        signer,
      );
      const tokenInContract = new ethers.Contract(
        tokenIn,
        UNISWAP_PAIR_ABI,
        signer,
      );
      const tokenInSymbol = await tokenInContract.symbol();
      const tokenOutContract = new ethers.Contract(
        tokenOut,
        UNISWAP_PAIR_ABI,
        signer,
      );
      const tokenOutSymbol = await tokenOutContract.symbol();
      const amountInWei = ethers.utils.parseUnits(amountIn.toString(), 'ether');
      const amountOutMinWei = ethers.utils.parseUnits(
        amountOutMin.toString(),
        'ether',
      );
      const deadline = Math.floor(Date.now() / 1000) + 60 * 20; // 20 minutes from the current Unix time
      const tx = await router.swapExactTokensForTokens(
        amountInWei,
        amountOutMinWei,
        [tokenIn, tokenOut],
        recipient,
        deadline,
      );
      await tx.wait();
      setTxHash(tx.hash);
    } catch (err: any) {
      setError(err.message);
    } finally {
      setIsLoading(false);
    }
  };
  return { swapTokens, isLoading, error, txHash };
};

// 根据输入 Token A 数量计算将要输出 Token B 的数量
export const useOutputAmount = (tokenA?: string, tokenB?: string) => {
  const [inputAmount, setInputAmount] = useState<string>('');
  const [outputAmount, setOutputAmount] = useState<string>('');
  const [tokenABalance, setTokenABalance] = useState<any>('');
  const [tokenBBalance, setTokenBBalance] = useState<any>('');

  const provider = new ethers.providers.Web3Provider(window.ethereum);
  console.log(provider, 'provider');
  const signer = provider.getSigner();
  const pairInstance = new ethers.Contract(
    PAIR_ADDRESS,
    UNISWAP_PAIR_ABI,
    provider,
  );
  const uniswapRouterInstance = new ethers.Contract(
    UNISWAP_ROUTER_ADDRESS,
    UNISWAP_ROUTER_ABI,
    provider,
  );
  const tokenAInstance = new ethers.Contract(
    TOKEN_A_ADDRESS,
    ERC20_ABI,
    provider.getSigner(), // 这里使用 Signer
  );

  const tokenBInstance = new ethers.Contract(
    TOKEN_B_ADDRESS,
    ERC20_ABI,
    provider.getSigner(), // 这里使用 Signer
  );

  const OutputAmountAB = async () => {
    try {
      const reserves = await pairInstance?.getReserves();
      const amountIn = ethers.utils.parseUnits(inputAmount || '0', 'ether');
      const amountOut = await uniswapRouterInstance?.getAmountsOut(amountIn, [
        TOKEN_A_ADDRESS || tokenA,
        TOKEN_B_ADDRESS || tokenB,
      ]);
      const outputAmountss = ethers.utils.formatUnits(
        (amountOut && amountOut[1]) || '0',
        'ether',
      );
      setOutputAmount(outputAmountss);
      console.log(amountOut, 'aaaaaaa', outputAmountss);
    } catch (error) {
      console.error(error);
    }
  };
  const getBalances = async () => {
    try {
      const nameA = await tokenAInstance.name();
      const nameB = await tokenBInstance.name();
      const symbolA = await tokenAInstance.symbol();
      const symbolB = await tokenBInstance.symbol();
      const tokenABalance = await tokenAInstance.balanceOf(PAIR_ADDRESS);
      const tokenBBalance = await tokenBInstance.balanceOf(PAIR_ADDRESS);

      const balanceA = BigNumber.from(tokenABalance).toString();
      const balanceB = BigNumber.from(tokenBBalance).toString();
      console.log(
        balanceA.toString(),
        'getBalancegetBalance',
        balanceB.toString(),
      );
      const etherBalanceA = ethers.utils.formatUnits(
        tokenABalance || '0',
        'ether',
      );
      const etherBalanceB = ethers.utils.formatUnits(
        tokenBBalance || '0',
        'ether',
      );
      console.error(etherBalanceA, etherBalanceB);
      setTokenABalance({
        balance: etherBalanceA,
        name: nameA,
        symbol: symbolA,
      });
      setTokenBBalance({
        balance: etherBalanceB,
        name: nameB,
        symbol: symbolB,
      });
    } catch (error) {
      console.error(error);
    }
  };

  return {
    tokenBBalance,
    tokenABalance,
    outputAmount,
    inputAmount,
    setInputAmount,
    setOutputAmount,
    OutputAmountAB,
    getBalances,
  };
};
